home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 253 / Issue 253 - March 2009 - DPCS0309DVD.ISO / Toolkit / Internet / WinHTTrack / httrack-3.43.exe / {app} / src / htscache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  66.8 KB  |  1,811 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       cache system (index and stores files in cache)         */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htscache.h"
  42.  
  43. /* specific definitions */
  44. #include "htscore.h"
  45. #include "htsbasenet.h"
  46. #include "htsmd5.h"
  47. #include <time.h>
  48.  
  49. #include "htszlib.h"
  50. /* END specific definitions */
  51.  
  52. #undef test_flush
  53. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->log); }
  54.  
  55. // routines de mise en cache
  56.  
  57. /*
  58.   VERSION 1.0 :
  59.   -----------
  60.  
  61. .ndx file
  62.  file with data
  63.    <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  64.  file without data
  65.    <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  66.  
  67. .dat file
  68.  [ file ] * 
  69. with
  70.   file= (with data)
  71.    [ bytes ] * sizeof(htsblk header) [ bytes ] * n(length of file given in htsblk header)
  72.  file= (without data)
  73.    [ bytes ] * sizeof(htsblk header)
  74. with
  75.  <string>(name) = <length in ascii>+<lf>+<data>
  76.  
  77.  
  78.   VERSION 1.1/1.2 :
  79.   ---------------
  80.  
  81. .ndx file
  82.  file with data
  83.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  84.  file without data
  85.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  86.  
  87. .dat file
  88.    <string>("CACHE-1.1") [ [Header_1.1] [bytes] * n(length of file given in header) ] *
  89. with
  90.  Header_1.1=
  91.    <int>(statuscode)
  92.    <int>(size)
  93.    <string>(msg)
  94.    <string>(contenttype)
  95.    <string>(charset) [version 3]
  96.    <string>(last-modified)
  97.    <string>(Etag)
  98.    <string>location
  99.    <string>Content-disposition [version 2]
  100.    <string>hostname [version 4]
  101.    <string>URI filename [version 4]
  102.    <string>local filename [version 4]
  103.    [<string>"SD" <string>(supplemental data)]
  104.    [<string>"SD" <string>(supplemental data)]
  105.    ...
  106.    <string>"HTS" (end of header)
  107.    <int>(number of bytes of data) (0 if no data written)
  108. */
  109.  
  110. // Nouveau: si != text/html ne stocke que la taille
  111.  
  112.  
  113. void cache_mayadd(httrackp* opt,cache_back* cache,htsblk* r,const char* url_adr,const char* url_fil,const char* url_save) {
  114.   if ((opt->debug>0) && (opt->log!=NULL)) {
  115.     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File checked by cache: %s"LF,url_adr);
  116.   }            
  117.   // ---stockage en cache---
  118.   // stocker dans le cache?
  119.   if (opt->cache) {
  120.     if (cache_writable(cache)) {
  121.       // ensure not a temporary filename (should not happend ?!)
  122.       if (IS_DELAYED_EXT(url_save)) {
  123.         if (opt->log!=NULL) {
  124.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log, "aborted cache validation: %s%s still has temporary name %s"LF, url_adr, url_fil, url_save);
  125.         }
  126.         return ;
  127.       }
  128.  
  129.       // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  130.       // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  131.       if (
  132. #if 1
  133.         r->statuscode > 0
  134. #else
  135.         /* We don't store 5XX errors, because it might be a server problem */
  136.         (r->statuscode==HTTP_OK)        /* stocker rΘponse standard, plus */
  137.         || (r->statuscode==204)     /* no content */
  138.         || HTTP_IS_REDIRECT(r->statuscode)    /* redirect */
  139.         || (r->statuscode==401)     /* authorization */
  140.         || (r->statuscode==403)     /* unauthorized */
  141.         || (r->statuscode==404)     /* not found */
  142.         || (r->statuscode==410)     /* gone */
  143. #endif
  144.         )
  145.       {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  146.         if (!r->is_file) {
  147.           // stocker fichiers (et robots.txt)
  148.           if ( url_save == NULL || (strnotempty(url_save)) || (strcmp(url_fil,"/robots.txt")==0)) {
  149.             // ajouter le fichier au cache
  150.                         cache_add(opt,cache,r,url_adr,url_fil,url_save,opt->all_in_cache,StringBuff(opt->path_html));
  151.             //
  152.             // store a reference NOT to redo the same test zillions of times!
  153.             // (problem reported by Lars Clausen)
  154.             // we just store statuscode + location (if any)
  155.             if (url_save == NULL && r->statuscode / 100 >= 3) {
  156.               // cached "fast" header doesn't uet exists
  157.               if (inthash_read(cache->cached_tests, concat(OPT_GET_BUFF(opt), url_adr, url_fil), NULL) == 0) {
  158.                 char BIGSTK tempo[HTS_URLMAXSIZE*2];
  159.                 sprintf(tempo, "%d", (int)r->statuscode);
  160.                 if (r->location != NULL && r->location[0] != '\0') {
  161.                   strcatbuff(tempo, "\n");
  162.                   strcatbuff(tempo, r->location);
  163.                 }
  164.                 if ((opt->debug>0) && (opt->log!=NULL)) {
  165.                   HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log, "Cached fast-header response: %s%s is %d"LF, url_adr, url_fil, (int)r->statuscode);
  166.                 }
  167.                 inthash_add(cache->cached_tests, concat(OPT_GET_BUFF(opt), url_adr, url_fil), (intptr_t)strdupt(tempo));
  168.               }
  169.             }
  170.           }
  171.         }
  172.       }
  173.     }
  174.   }
  175.   // ---fin stockage en cache---
  176. }
  177.  
  178. #if 1
  179.  
  180. #define ZIP_FIELD_STRING(headers, headersSize, field, value) do { \
  181.   if ( (value != NULL) && (value)[0] != '\0') { \
  182.     sprintf(headers + headersSize, "%s: %s\r\n", field, (value != NULL) ? (value) : ""); \
  183.     (headersSize) += (int) strlen(headers + headersSize); \
  184.   } \
  185. } while(0)
  186. #define ZIP_FIELD_INT(headers, headersSize, field, value) do { \
  187.   if ( (value != 0) ) { \
  188.     sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  189.     (headersSize) += (int) strlen(headers + headersSize); \
  190.   } \
  191. } while(0)
  192. #define ZIP_FIELD_INT_FORCE(headers, headersSize, field, value) do { \
  193.   sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  194.   (headersSize) += (int) strlen(headers + headersSize); \
  195. } while(0)
  196.  
  197. struct cache_back_zip_entry {
  198.   unsigned long int hdrPos;
  199.   unsigned long int size;
  200.   int compressionMethod;
  201. };
  202.  
  203. #define ZIP_READFIELD_STRING(line, value, refline, refvalue) do { \
  204.   if (line[0] != '\0' && strfield2(line, refline)) { \
  205.     strcpybuff(refvalue, value); \
  206.     line[0] = '\0'; \
  207.     } \
  208. } while(0)
  209. #define ZIP_READFIELD_INT(line, value, refline, refvalue) do { \
  210.   if (line[0] != '\0' && strfield2(line, refline)) { \
  211.     int intval = 0; \
  212.     sscanf(value, "%d", &intval); \
  213.     (refvalue) = intval; \
  214.     line[0] = '\0'; \
  215.     } \
  216. } while(0)
  217.  
  218.  
  219. /* Ajout d'un fichier en cache */
  220. void cache_add(httrackp* opt,cache_back* cache,const htsblk *r,const char* url_adr,const char* url_fil,const char* url_save,int all_in_cache,const char* path_prefix) {
  221.   char BIGSTK filename[HTS_URLMAXSIZE*4];
  222.     char catbuff[CATBUFF_SIZE];
  223.   int dataincache=0;    // put data in cache ?
  224.   char BIGSTK headers[8192];
  225.   int headersSize = 0;
  226.   int entryBodySize = 0;
  227.   int entryFilenameSize = 0;
  228.   zip_fileinfo fi;
  229.     const char* url_save_suffix = url_save;
  230.     int zErr;
  231.  
  232.   // robots.txt hack
  233.   if (url_save == NULL) {
  234.     dataincache=0;        // testing links
  235.   }
  236.   else {
  237.     if ( (strnotempty(url_save)==0) ) {
  238.       if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  239.         dataincache=1;
  240.       else
  241.         return;   // error (except robots.txt)
  242.     }
  243.  
  244.     /* Data in cache ? */
  245.     if (is_hypertext_mime(opt,r->contenttype, url_fil)
  246.             || (may_be_hypertext_mime(opt,r->contenttype, url_fil) && r->adr != NULL)
  247.             )
  248.         {
  249.       dataincache=1;
  250.         } else if (all_in_cache) {
  251.       dataincache=1;
  252.         }
  253.   }
  254.  
  255.   if (r->size < 0)   // error
  256.     return;
  257.  
  258.   // data in cache
  259.   if (dataincache) {
  260.     assertf(((int) r->size) == r->size);
  261.     entryBodySize = (int) r->size;
  262.   }
  263.  
  264.   /* Fields */
  265.   headers[0] = '\0';
  266.   headersSize = 0;
  267.   /* */
  268.   {
  269.     const char* message;
  270.     if (strlen(r->msg) < 32) {
  271.       message = r->msg;
  272.     } else {
  273.       message = "(See X-StatusMessage)";
  274.     }
  275.     /* 64 characters MAX for first line */
  276.     sprintf(headers + headersSize, "HTTP/1.%c %d %s\r\n", '1', r->statuscode, r->msg);
  277.   }
  278.   headersSize += (int) strlen(headers + headersSize);
  279.  
  280.     if (path_prefix != NULL && path_prefix[0] != '\0' && url_save != NULL && url_save[0] != '\0') {
  281.         int prefixLen = (int) strlen(path_prefix);
  282.         if (strncmp(url_save, path_prefix, prefixLen) == 0) {
  283.             url_save_suffix += prefixLen;
  284.         }
  285.     }
  286.  
  287.   /* Second line MUST ALWAYS be X-In-Cache */
  288.   ZIP_FIELD_INT_FORCE(headers, headersSize, "X-In-Cache", dataincache);
  289.   ZIP_FIELD_INT(headers, headersSize, "X-StatusCode", r->statuscode);
  290.   ZIP_FIELD_STRING(headers, headersSize, "X-StatusMessage", r->msg);
  291.   ZIP_FIELD_INT(headers, headersSize, "X-Size", r->size);           // size
  292.   ZIP_FIELD_STRING(headers, headersSize, "Content-Type", r->contenttype);      // contenttype
  293.   ZIP_FIELD_STRING(headers, headersSize, "X-Charset", r->charset);          // contenttype
  294.   ZIP_FIELD_STRING(headers, headersSize, "Last-Modified", r->lastmodified);     // last-modified
  295.   ZIP_FIELD_STRING(headers, headersSize, "Etag", r->etag);             // Etag
  296.   ZIP_FIELD_STRING(headers, headersSize, "Location", r->location);         // 'location' pour moved
  297.   ZIP_FIELD_STRING(headers, headersSize, "Content-Disposition", r->cdispo);           // Content-disposition
  298.   ZIP_FIELD_STRING(headers, headersSize, "X-Addr", url_adr);            // Original address
  299.   ZIP_FIELD_STRING(headers, headersSize, "X-Fil", url_fil);            // Original URI filename
  300.   ZIP_FIELD_STRING(headers, headersSize, "X-Save", url_save_suffix);           // Original save filename
  301.   
  302.   entryFilenameSize = (int) ( strlen(url_adr) + strlen(url_fil));
  303.   
  304.   /* Filename */
  305.   if (!link_has_authority(url_adr)) {
  306.     strcpybuff(filename, "http://");
  307.   } else {
  308.     strcpybuff(filename, "");
  309.   }
  310.   strcatbuff(filename, url_adr);
  311.   strcatbuff(filename, url_fil);
  312.  
  313.   /* Time */
  314.   memset(&fi, 0, sizeof(fi));
  315.   if (r->lastmodified[0] != '\0') {
  316.         struct tm buffer;
  317.     struct tm* tm_s=convert_time_rfc822(&buffer, r->lastmodified);
  318.     if (tm_s) {
  319.       fi.tmz_date.tm_sec = (uInt) tm_s->tm_sec;
  320.       fi.tmz_date.tm_min = (uInt) tm_s->tm_min;
  321.       fi.tmz_date.tm_hour = (uInt) tm_s->tm_hour;
  322.       fi.tmz_date.tm_mday = (uInt) tm_s->tm_mday;
  323.       fi.tmz_date.tm_mon = (uInt) tm_s->tm_mon;
  324.       fi.tmz_date.tm_year = (uInt) tm_s->tm_year;
  325.     }
  326.   }
  327.   
  328.   /* Open file - NOTE: headers in "comment" */
  329.   if ((zErr = zipOpenNewFileInZip((zipFile) cache->zipOutput,
  330.     filename,
  331.     &fi,
  332.     /* 
  333.     Store headers in realtime in the local file directory as extra field
  334.     In case of crash, we'll be able to recover the whole ZIP file by rescanning it
  335.     */
  336.     headers,
  337.     (uInt) strlen(headers),
  338.     NULL,
  339.     0,
  340.     NULL, /* comment */
  341.     Z_DEFLATED,
  342.     Z_DEFAULT_COMPRESSION)) != Z_OK)
  343.   {
  344.     int zip_zipOpenNewFileInZip_failed = 0;
  345.     assertf(zip_zipOpenNewFileInZip_failed);
  346.   }
  347.   
  348.   /* Write data in cache */
  349.   if (dataincache) {
  350.     if (r->is_write == 0) {
  351.       if (r->size > 0 && r->adr != NULL) {
  352.         if ((zErr = zipWriteInFileInZip((zipFile) cache->zipOutput, r->adr, (int) r->size)) != Z_OK) {
  353.           int zip_zipWriteInFileInZip_failed = 0;
  354.           assertf(zip_zipWriteInFileInZip_failed);
  355.         }
  356.       }
  357.     } else {
  358.       FILE* fp;
  359.       // On recopie le fichier->.
  360.       off_t file_size=fsize(fconv(catbuff, url_save));
  361.       if (file_size>=0) {
  362.         fp=fopen(fconv(catbuff, url_save),"rb");
  363.         if (fp!=NULL) {
  364.           char BIGSTK buff[32768];
  365.           size_t nl;
  366.           do {
  367.             nl=fread(buff,1,32768,fp);
  368.             if (nl>0) { 
  369.               if ((zErr = zipWriteInFileInZip((zipFile) cache->zipOutput, buff, (int) nl)) != Z_OK) {
  370.                 int zip_zipWriteInFileInZip_failed = 0;
  371.                 assertf(zip_zipWriteInFileInZip_failed);
  372.               }
  373.             }
  374.           } while(nl>0);
  375.           fclose(fp);
  376.         } else {
  377.           /* Err FIXME - lost file */
  378.         }
  379.       } /* Empty files are OK */
  380.     }
  381.   }
  382.   
  383.   /* Close */
  384.   if ((zErr = zipCloseFileInZip((zipFile) cache->zipOutput)) != Z_OK) {
  385.     int zip_zipCloseFileInZip_failed = 0;
  386.     assertf(zip_zipCloseFileInZip_failed);
  387.   }
  388.  
  389.   /* Flush */
  390.   if ((zErr = zipFlush((zipFile) cache->zipOutput)) != 0) {
  391.     int zip_zipFlush_failed = 0;
  392.     assertf(zip_zipFlush_failed);
  393.   }
  394. }
  395.  
  396. #else
  397.  
  398. /* Ajout d'un fichier en cache */
  399. void cache_add(httrackp* opt,cache_back* cache,const htsblk *r,char* url_adr,char* url_fil,char* url_save,int all_in_cache) {
  400.   int pos;
  401.   char s[256];
  402.   char BIGSTK buff[HTS_URLMAXSIZE*4];
  403.   int ok=1;
  404.   int dataincache=0;    // donnΘe en cache?
  405.   FILE* cache_ndx = cache->ndx;
  406.   FILE* cache_dat = cache->dat;
  407.   /*char digest[32+2];*/
  408.   /*digest[0]='\0';*/
  409.  
  410.   // Longueur url_save==0?
  411.   if ( (strnotempty(url_save)==0) ) {
  412.     if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  413.       dataincache=1;
  414.     else if (strcmp(url_fil,"/test")==0)        // testing links
  415.       dataincache=0;
  416.     else
  417.       return;   // erreur (sauf robots.txt)
  418.   }
  419.  
  420.   if (r->size <= 0)   // taille <= 0 
  421.     return;          // refusΘ..
  422.  
  423.   // Mettre les *donΘes* en cache ?
  424.   if (is_hypertext_mime(opt,r->contenttype, url_fil))    // html, mise en cache des donnΘes et 
  425.     dataincache=1;                               // pas uniquement de l'en tΩte
  426.   else if (all_in_cache)
  427.     dataincache=1;                               // forcer tout en cache
  428.  
  429.   /* calcul md5 ? */
  430.   /*
  431.   if (is_hypertext_mime(opt,r->contenttype)) {    // html, calcul MD5
  432.     if (r->adr) {
  433.       domd5mem(r->adr,r->size,digest,1);
  434.     }
  435.   }*/
  436.  
  437.   // Position
  438.   fflush(cache_dat); fflush(cache_ndx);
  439.   pos=ftell(cache_dat);
  440.   // Θcrire pointeur seek, adresse, fichier
  441.   if (dataincache)   // patcher
  442.     sprintf(s,"%d\n",pos);    // ecrire tel que (eh oui Θvite les \0..)
  443.   else
  444.     sprintf(s,"%d\n",-pos);   // ecrire tel que (eh oui Θvite les \0..)
  445.  
  446.   // data
  447.   // Θcrire donnΘes en-tΩte, donnΘes fichier
  448.   /*if (!dataincache) {   // patcher
  449.     r->size=-r->size;  // nΘgatif
  450.   }*/
  451.  
  452.   // Construction header
  453.   ok=0;
  454.   if (cache_wint(cache_dat,r->statuscode) != -1       // statuscode
  455.   && cache_wLLint(cache_dat,r->size) != -1           // size
  456.   && cache_wstr(cache_dat,r->msg) != -1              // msg
  457.   && cache_wstr(cache_dat,r->contenttype) != -1      // contenttype
  458.   && cache_wstr(cache_dat,r->charset) != -1          // contenttype
  459.   && cache_wstr(cache_dat,r->lastmodified) != -1     // last-modified
  460.   && cache_wstr(cache_dat,r->etag) != -1             // Etag
  461.   && cache_wstr(cache_dat,(r->location!=NULL)?r->location:"") != -1         // 'location' pour moved
  462.   && cache_wstr(cache_dat,r->cdispo) != -1           // Content-disposition
  463.   && cache_wstr(cache_dat,url_adr) != -1            // Original address
  464.   && cache_wstr(cache_dat,url_fil) != -1            // Original URI filename
  465.   && cache_wstr(cache_dat,url_save) != -1           // Original save filename
  466.   && cache_wstr(cache_dat,r->headers) != -1          // Full HTTP Headers
  467.   && cache_wstr(cache_dat,"HTS") != -1              // end of header
  468.   ) {
  469.     ok=1;       /* ok */
  470.   }
  471.   // Fin construction header
  472.  
  473.   /*if ((int) fwrite((char*) &r,1,sizeof(htsblk),cache_dat) == sizeof(htsblk)) {*/
  474.   if (ok) {
  475.     if (dataincache) {    // mise en cache?
  476.       if (!r->adr) {       /* taille nulle (parfois en cas de 301 */
  477.         if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  478.           ok=0;
  479.       } else if (r->is_write==0) {  // en mΘmoire, recopie directe
  480.         if (cache_wLLint(cache_dat,r->size)!=-1) {
  481.           if (r->size>0) {   // taille>0
  482.             if (fwrite(r->adr,1,r->size,cache_dat)!=r->size)
  483.               ok=0;
  484.           } else    // taille=0, ne rien Θcrire
  485.             ok=0;
  486.         } else
  487.           ok=0;
  488.       } else {  // recopier fichier dans cache
  489.         FILE* fp;
  490.         // On recopie le fichier->.
  491.         off_t file_size=fsize(fconv(catbuff, url_save));
  492.         if (file_size>=0) {
  493.           if (cache_wLLint(cache_dat,file_size)!=-1) {
  494.             fp=fopen(fconv(catbuff, url_save),"rb");
  495.             if (fp!=NULL) {
  496.               char BIGSTK buff[32768];
  497.               ssize_t nl;
  498.               do {
  499.                 nl=fread(buff,1,32768,fp);
  500.                 if (nl>0) { 
  501.                   if (fwrite(buff,1,nl,cache_dat)!=nl) {  // erreur
  502.                     nl=-1;
  503.                     ok=0;
  504.                   }
  505.                 }
  506.               } while(nl>0);
  507.               fclose(fp);
  508.             } else ok=0;
  509.           } else ok=0;
  510.         } else ok=0;
  511.       }
  512.     } else {
  513.       if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  514.         ok=0;
  515.     }
  516.   } else ok=0;
  517.   /*if (!dataincache) {   // dΘpatcher
  518.     r->size=-r->size;
  519.   }*/
  520.  
  521.   // index
  522.   // adresse+cr+fichier+cr
  523.   if (ok) {
  524.     buff[0]='\0'; strcatbuff(buff,url_adr); strcatbuff(buff,"\n"); strcatbuff(buff,url_fil); strcatbuff(buff,"\n");
  525.     cache_wstr(cache_ndx,buff);
  526.     fwrite(s,1,strlen(s),cache_ndx);
  527.   }  // si ok=0 on a peut Ωtre Θcrit des donnΘes pour rien mais on s'en tape
  528.   
  529.   // en cas de plantage, on aura au moins le cache!
  530.   fflush(cache_dat); fflush(cache_ndx);
  531. }
  532.  
  533. #endif
  534.  
  535.  
  536. htsblk cache_read(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location) {
  537.   return cache_readex(opt,cache,adr,fil,save,location,NULL,0);
  538. }
  539.  
  540. htsblk cache_read_ro(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location) {
  541.   return cache_readex(opt,cache,adr,fil,save,location,NULL,1);
  542. }
  543.  
  544. htsblk cache_read_including_broken(httrackp* opt,cache_back* cache,const char* adr,const char* fil) {
  545.   htsblk r = cache_read(opt,cache,adr,fil,NULL,NULL);
  546.   if (r.statuscode = -1) {
  547.     lien_back *itemback = NULL;
  548.     if (back_unserialize_ref(opt, adr, fil, &itemback) == 0) {
  549.       r = itemback->r;
  550.       /* cleanup */
  551.       back_clear_entry(itemback);                /* delete entry content */
  552.       freet(itemback);                                    /* delete item */
  553.       itemback = NULL;
  554.       return r;
  555.     }
  556.   }
  557.   return r;
  558. }
  559.  
  560. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location,
  561.                                char* return_save, int readonly);
  562.  
  563. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location,
  564.                                char* return_save, int readonly);
  565.  
  566. // lecture d'un fichier dans le cache
  567. // si save==null alors test unqiquement
  568. htsblk cache_readex(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location,
  569.                     char* return_save, int readonly) {
  570.   if (cache->zipInput != NULL) {
  571.     return cache_readex_new(opt, cache, adr, fil, save, location, return_save, readonly);
  572.   } else {
  573.     return cache_readex_old(opt, cache, adr, fil, save, location, return_save, readonly);
  574.   }
  575. }
  576.  
  577. // lecture d'un fichier dans le cache
  578. // si save==null alors test unqiquement
  579. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location,
  580.                                char* return_save, int readonly) {
  581.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  582.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  583.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  584.   char BIGSTK previous_save_[HTS_URLMAXSIZE*2];
  585.     char catbuff[CATBUFF_SIZE];
  586.   intptr_t hash_pos;
  587.   int hash_pos_return;
  588.   htsblk r;
  589.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  590.     location_default[0] = '\0';
  591.     previous_save[0] = previous_save_[0] = '\0';
  592.  
  593.   if (location) {
  594.     r.location = location;
  595.   } else {
  596.     r.location = location_default;
  597.   }
  598.   strcpybuff(r.location, ""); 
  599.   strcpybuff(buff, adr);
  600.   strcatbuff(buff,fil);
  601.   hash_pos_return = inthash_read(cache->hashtable, buff, &hash_pos);
  602.   /* avoid errors on data entries */
  603.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  604. #if HTS_FAST_CACHE
  605.     hash_pos_return = 0;
  606. #else
  607.     a = NULL;
  608. #endif
  609.   }
  610.  
  611.   if (hash_pos_return) {
  612.     uLong posInZip;
  613.     if (hash_pos > 0) {
  614.       posInZip = (uLong) hash_pos;
  615.     } else {
  616.       posInZip = (uLong) -hash_pos;
  617.     }
  618.     if (unzSetOffset((unzFile) cache->zipInput, posInZip) == Z_OK) {
  619.       /* Read header (Max 8KiB) */
  620.       if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  621.         char BIGSTK headerBuff[8192 + 2];
  622.         int readSizeHeader;
  623.         int totalHeader = 0;
  624.         int dataincache = 0;
  625.         
  626.         /* For BIG comments */
  627.         headerBuff[0] 
  628.           = headerBuff[sizeof(headerBuff) - 1] 
  629.           = headerBuff[sizeof(headerBuff) - 2] 
  630.           = headerBuff[sizeof(headerBuff) - 3] = '\0';
  631.  
  632.         if ( (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, headerBuff, sizeof(headerBuff) - 2)) > 0) 
  633.         /*if (unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL,
  634.           NULL, 0, NULL, 0, headerBuff, sizeof(headerBuff) - 2) == Z_OK ) */
  635.         {
  636.           int offset = 0;
  637.           char BIGSTK line[HTS_URLMAXSIZE + 2];
  638.           int lineEof = 0;
  639.           /*readSizeHeader = (int) strlen(headerBuff);*/
  640.           headerBuff[readSizeHeader] = '\0';
  641.           do {
  642.             char* value;
  643.             line[0] = '\0';
  644.             offset += binput(headerBuff + offset, line, sizeof(line) - 2);
  645.             if (line[0] == '\0') {
  646.               lineEof = 1;
  647.             }
  648.             value = strchr(line, ':');
  649.             if (value != NULL) {
  650.               *value++ = '\0';
  651.               if (*value == ' ' || *value == '\t') value++;
  652.               ZIP_READFIELD_INT(line, value, "X-In-Cache", dataincache);
  653.               ZIP_READFIELD_INT(line, value, "X-Statuscode", r.statuscode);
  654.               ZIP_READFIELD_STRING(line, value, "X-StatusMessage", r.msg);              // msg
  655.               ZIP_READFIELD_INT(line, value, "X-Size", r.size);           // size
  656.               ZIP_READFIELD_STRING(line, value, "Content-Type", r.contenttype);      // contenttype
  657.               ZIP_READFIELD_STRING(line, value, "X-Charset", r.charset);          // contenttype
  658.               ZIP_READFIELD_STRING(line, value, "Last-Modified", r.lastmodified);     // last-modified
  659.               ZIP_READFIELD_STRING(line, value, "Etag", r.etag);             // Etag
  660.               ZIP_READFIELD_STRING(line, value, "Location", r.location);         // 'location' pour moved
  661.               ZIP_READFIELD_STRING(line, value, "Content-Disposition", r.cdispo);           // Content-disposition
  662.               //ZIP_READFIELD_STRING(line, value, "X-Addr", ..);            // Original address
  663.               //ZIP_READFIELD_STRING(line, value, "X-Fil", ..);            // Original URI filename
  664.               ZIP_READFIELD_STRING(line, value, "X-Save", previous_save_);           // Original save filename
  665.             }
  666.           } while(offset < readSizeHeader && !lineEof);
  667.           totalHeader = offset;
  668.  
  669.                     /* Previous entry */
  670.                     if (previous_save_[0] != '\0') {
  671.                         int pathLen = (int) strlen(StringBuff(opt->path_html));
  672.                         if (pathLen != 0 && strncmp(previous_save_, StringBuff(opt->path_html), pathLen) != 0) {            // old (<3.40) buggy format
  673.                             sprintf(previous_save, "%s%s", StringBuff(opt->path_html), previous_save_);
  674.                         } else {
  675.                             strcpy(previous_save, previous_save_);
  676.                         }
  677.                     }
  678.           if (return_save != NULL) {
  679.             strcpybuff(return_save, previous_save);
  680.           }
  681.  
  682.           /* Complete fields */
  683.           r.totalsize=r.size;
  684.           r.adr=NULL;
  685.           r.out=NULL;
  686.           r.fp=NULL;
  687.           
  688.           if (save != NULL) {     /* ne pas lire uniquement header */
  689.             int ok = 0;
  690.                        
  691. #if HTS_DIRECTDISK
  692.             // Court-circuit:
  693.             // Peut-on stocker le fichier directement sur disque?
  694.             if (ok) {
  695.               if (r.msg[0] == '\0') {
  696.                 strcpybuff(r.msg,"Cache Read Error : Unexpected error");
  697.               }
  698.             }
  699.             else if (!readonly && r.statuscode==HTTP_OK && !is_hypertext_mime(opt,r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  700.               r.is_write=1;    // Θcrire
  701.  
  702.               if (!dataincache) {
  703.                                 if (fexist(fconv(catbuff, save))) {  // un fichier existe dΘja
  704.                                     //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  705.                                     ok=1;    // plus rien α faire
  706.                                     filenote(&opt->state.strc,save,NULL);        // noter comme connu
  707.                                     file_notify(opt,adr, fil, save, 0, 0, 1);        // data in cache
  708.                                 }
  709.                             }
  710.               
  711.               if (!dataincache && !ok) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  712.                 if (opt->norecatch) {
  713.                   file_notify(opt,adr, fil, save, 1, 0, 0);
  714.                   filecreateempty(&opt->state.strc, save);
  715.                   //
  716.                   r.statuscode=STATUSCODE_INVALID;
  717.                   strcpybuff(r.msg,"File deleted by user not recaught");
  718.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  719.                 } else {
  720.                   // ????? file_notify(opt,adr, fil, save, 1, 1, 0);
  721.                   r.statuscode=STATUSCODE_INVALID;
  722.                   strcpybuff(r.msg,"Previous cache file not found");
  723.                   ok=1;    // ne pas rΘcupΘrer
  724.                 }
  725.               }
  726.               
  727.               if (!ok) {        // load from cache
  728.                 file_notify(opt,adr, fil, save, 1, 1, 1);        // data in cache
  729.                 r.out=filecreate(&opt->state.strc, save);
  730. #if HDEBUG
  731.                 printf("direct-disk: %s\n",save);
  732. #endif
  733.                 if (r.out!=NULL) {
  734.                   char BIGSTK buff[32768+4];
  735.                   LLint size = r.size;
  736.                   if (size > 0) {
  737.                     size_t nl;
  738.                     do {
  739.                       nl = unzReadCurrentFile((unzFile) cache->zipInput, buff, (int)minimum(size, 32768));
  740.                       if (nl>0) {
  741.                         size-=nl; 
  742.                         if (fwrite(buff,1,nl,r.out)!=nl) {  // erreur
  743.                           int last_errno = errno;
  744.                           r.statuscode=STATUSCODE_INVALID;
  745.                           sprintf(r.msg,"Cache Read Error : Read To Disk: %s", strerror(last_errno));
  746.                         }
  747.                       }
  748.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  749.                   }
  750.                   
  751.                   fclose(r.out);
  752.                   r.out=NULL;
  753. #ifndef _WIN32
  754.                   chmod(save,HTS_ACCESS_FILE);      
  755. #endif          
  756.                 } else {
  757.                   r.statuscode=STATUSCODE_INVALID;
  758.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  759.                   //printf("%s\n",save);
  760.                 }
  761.               }
  762.               
  763.             } else
  764. #endif
  765.             { // lire en mΘmoire
  766.               
  767.               if (!dataincache) {
  768.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  769.                   r.statuscode=STATUSCODE_INVALID;
  770.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  771.                 } else {                 /* Read in memory from cache */
  772.                   if (strnotempty(previous_save) && fexist(previous_save)) {
  773.                     FILE* fp = fopen(fconv(catbuff, previous_save), "rb");
  774.                     if (fp != NULL) {
  775.                       r.adr = (char*) malloct((int) r.size + 4);
  776.                       if (r.adr != NULL) {
  777.                         if (r.size > 0 && fread(r.adr, 1, (int) r.size, fp) != r.size) {
  778.                           int last_errno = errno;
  779.                           r.statuscode=STATUSCODE_INVALID;
  780.                           sprintf(r.msg,"Read error in cache disk data: %s", strerror(last_errno));
  781.                         }
  782.                       } else {
  783.                         r.statuscode=STATUSCODE_INVALID;
  784.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  785.                       }
  786.                       fclose(fp);
  787.                     }
  788.                   } else {
  789.                     r.statuscode=STATUSCODE_INVALID;
  790.                     strcpybuff(r.msg,"Cache file not found on disk");
  791.                   }
  792.                 }
  793.               } else {
  794.                 // lire fichier (d'un coup)
  795.                 r.adr = (char*) malloct((int) r.size+4);
  796.                 if (r.adr!=NULL) {
  797.                   if (unzReadCurrentFile((unzFile) cache->zipInput, r.adr, (int) r.size) != r.size) {  // erreur
  798.                     freet(r.adr);
  799.                     r.adr=NULL;
  800.                     r.statuscode=STATUSCODE_INVALID;
  801.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  802.                   } else
  803.                     *(r.adr+r.size)='\0';
  804.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  805.                 } else {  // erreur
  806.                   r.statuscode=STATUSCODE_INVALID;
  807.                   strcpybuff(r.msg,"Cache Memory Error");
  808.                 }
  809.               }
  810.             }
  811.           }
  812.           // si save==null, ne rien charger (juste en tΩte)
  813.           else if (r.statuscode==HTTP_OK && !is_hypertext_mime(opt,r.contenttype, fil)) {    // pas HTML, Θcrire sur disk directement
  814.             r.is_write = 1;  /* supposed to be on disk (informational) */
  815.           }
  816.  
  817.         } else {
  818.           r.statuscode=STATUSCODE_INVALID;
  819.           strcpybuff(r.msg,"Cache Read Error : Read Header Data");
  820.         }
  821.         unzCloseCurrentFile((unzFile) cache->zipInput);
  822.       } else {
  823.         r.statuscode=STATUSCODE_INVALID;
  824.         strcpybuff(r.msg,"Cache Read Error : Open File");
  825.       }
  826.  
  827.     } else {
  828.       r.statuscode=STATUSCODE_INVALID;
  829.       strcpybuff(r.msg,"Cache Read Error : Bad Offset");
  830.     }
  831.   } else {
  832.     r.statuscode=STATUSCODE_INVALID;
  833.     strcpybuff(r.msg,"File Cache Entry Not Found");
  834.   }
  835.   if (!location) {   /* don't export internal buffer */
  836.     r.location = NULL;
  837.   }
  838.   return r;
  839. }
  840.  
  841.  
  842. // lecture d'un fichier dans le cache
  843. // si save==null alors test unqiquement
  844. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,const char* adr,const char* fil,const char* save,char* location,
  845.                                char* return_save, int readonly) {
  846. #if HTS_FAST_CACHE
  847.   intptr_t hash_pos;
  848.   int hash_pos_return;
  849. #else
  850.   char* a;
  851. #endif
  852.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  853.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  854.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  855.     char catbuff[CATBUFF_SIZE];
  856.   htsblk r;
  857.   int ok=0;
  858.   int header_only=0;
  859.  
  860.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  861.   if (location) {
  862.     r.location = location;
  863.   } else {
  864.     r.location = location_default;
  865.   }
  866.   strcpybuff(r.location, ""); 
  867. #if HTS_FAST_CACHE
  868.   strcpybuff(buff,adr); strcatbuff(buff,fil);
  869.   hash_pos_return=inthash_read(cache->hashtable,buff,&hash_pos);
  870. #else
  871.   buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  872.   if (cache->use)
  873.     a=strstr(cache->use,buff);
  874.   else
  875.     a=NULL;       // forcer erreur
  876. #endif
  877.  
  878.   /* avoid errors on data entries */
  879.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  880. #if HTS_FAST_CACHE
  881.     hash_pos_return = 0;
  882. #else
  883.     a = NULL;
  884. #endif
  885.   }
  886.  
  887.   // en cas de succΦs
  888. #if HTS_FAST_CACHE
  889.   if (hash_pos_return) {
  890. #else
  891.   if (a!=NULL) {  // OK existe en cache!
  892. #endif
  893.     intptr_t pos;
  894. #if DEBUGCA
  895.     fprintf(stdout,"..cache: %s%s at ",adr,fil);
  896. #endif
  897.     
  898. #if HTS_FAST_CACHE
  899.     pos = hash_pos;     /* simply */
  900. #else
  901.     a+=strlen(buff);
  902.     sscanf(a,"%d",&pos);    // lire position
  903. #endif
  904. #if DEBUGCA
  905.     printf("%d\n",pos);
  906. #endif
  907.  
  908.     fflush(cache->olddat); 
  909.     if (fseek(cache->olddat,(long)((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  910.       /* Importer cache1.0 */
  911.       if (cache->version==0) {
  912.         OLD_htsblk old_r;
  913.         if (fread((char*) &old_r,1,sizeof(old_r),cache->olddat)==sizeof(old_r)) { // lire tout (y compris statuscode etc)
  914.           r.statuscode=old_r.statuscode;
  915.           r.size=old_r.size;        // taille fichier
  916.           strcpybuff(r.msg,old_r.msg);
  917.           strcpybuff(r.contenttype,old_r.contenttype);
  918.           ok=1;     /* import  ok */
  919.         }
  920.       /* */
  921.       /* Cache 1.1 */
  922.       } else {
  923.         char check[256];
  924.         LLint size_read;
  925.         check[0]='\0';
  926.         //
  927.         cache_rint(cache->olddat,&r.statuscode);
  928.         cache_rLLint(cache->olddat,&r.size);
  929.         cache_rstr(cache->olddat,r.msg);
  930.         cache_rstr(cache->olddat,r.contenttype);
  931.         if (cache->version >= 3)
  932.           cache_rstr(cache->olddat,r.charset);
  933.         cache_rstr(cache->olddat,r.lastmodified);
  934.         cache_rstr(cache->olddat,r.etag);
  935.         cache_rstr(cache->olddat,r.location);
  936.         if (cache->version >= 2)
  937.           cache_rstr(cache->olddat,r.cdispo);
  938.         if (cache->version >= 4) {
  939.           cache_rstr(cache->olddat, previous_save);  // adr
  940.           cache_rstr(cache->olddat, previous_save);  // fil
  941.           previous_save[0] = '\0';
  942.           cache_rstr(cache->olddat, previous_save);  // save
  943.           if (return_save != NULL) {
  944.             strcpybuff(return_save, previous_save);
  945.           }
  946.         }
  947.         if (cache->version >= 5) {
  948.           r.headers = cache_rstr_addr(cache->olddat);
  949.         }
  950.         //
  951.         cache_rstr(cache->olddat,check);
  952.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  953.           ok=1;
  954.         }
  955.         cache_rLLint(cache->olddat,&size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  956.         if (size_read>0) {                         /* si inscrite ici */
  957.           r.size=size_read;
  958.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  959.           if (r.statuscode!=HTTP_OK)
  960.             header_only=1;          /* que l'en tΩte ici! */
  961.         }
  962.       }
  963.  
  964.       /* Remplir certains champs */
  965.       r.totalsize=r.size;
  966.  
  967.       // lecture du header (y compris le statuscode)
  968.       /*if (fread((char*) &r,1,sizeof(htsblk),cache->olddat)==sizeof(htsblk)) { // lire tout (y compris statuscode etc)*/
  969.       if (ok) {
  970.         // sΘcuritΘ
  971.         r.adr=NULL;
  972.         r.out=NULL;
  973.         ////r.location=NULL;  non, fixΘe lors des 301 ou 302
  974.         r.fp=NULL;
  975.         
  976.         if ( (r.statuscode>=0) && (r.statuscode<=999)
  977.           && (r.notmodified>=0)  && (r.notmodified<=9) ) {   // petite vΘrif intΘgritΘ
  978.           if ((save) && (!header_only) ) {     /* ne pas lire uniquement header */
  979.             //int to_file=0;
  980.             
  981.             r.adr=NULL; r.soc=INVALID_SOCKET; 
  982.             // // r.location=NULL;
  983.             
  984. #if HTS_DIRECTDISK
  985.             // Court-circuit:
  986.             // Peut-on stocker le fichier directement sur disque?
  987.             if (!readonly && r.statuscode==HTTP_OK && !is_hypertext_mime(opt,r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  988.               int ok=0;
  989.               
  990.               r.is_write=1;    // Θcrire
  991.               if (fexist(fconv(catbuff, save))) {  // un fichier existe dΘja
  992.                 //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  993.                 ok=1;    // plus rien α faire
  994.                 filenote(&opt->state.strc,save,NULL);        // noter comme connu
  995.                 file_notify(opt,adr, fil, save, 0, 0, 0);
  996.                 //}
  997.               }
  998.               
  999.               if ((pos<0) && (!ok)) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  1000.                 if (opt->norecatch) {
  1001.                   file_notify(opt,adr, fil, save, 1, 0, 0);
  1002.                   filecreateempty(&opt->state.strc, save);
  1003.                   //
  1004.                   r.statuscode=STATUSCODE_INVALID;
  1005.                   strcpybuff(r.msg,"File deleted by user not recaught");
  1006.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  1007.                 } else {
  1008.                   r.statuscode=STATUSCODE_INVALID;
  1009.                   strcpybuff(r.msg,"Previous cache file not found");
  1010.                   ok=1;    // ne pas rΘcupΘrer
  1011.                 }
  1012.               }
  1013.               
  1014.               if (!ok) {  
  1015.                 r.out=filecreate(&opt->state.strc, save);
  1016. #if HDEBUG
  1017.                 printf("direct-disk: %s\n",save);
  1018. #endif
  1019.                 if (r.out!=NULL) {
  1020.                   char BIGSTK buff[32768+4];
  1021.                   size_t size = (size_t) r.size;
  1022.                   if (size > 0) {
  1023.                     size_t nl;
  1024.                     do {
  1025.                       nl=fread(buff,1,minimum(size,32768),cache->olddat);
  1026.                       if (nl>0) {
  1027.                         size-=nl; 
  1028.                         if (fwrite(buff,1,nl,r.out)!=nl) {  // erreur
  1029.                           r.statuscode=STATUSCODE_INVALID;
  1030.                           strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  1031.                         }
  1032.                       }
  1033.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  1034.                   }
  1035.                   
  1036.                   fclose(r.out);
  1037.                   r.out=NULL;
  1038. #ifndef _WIN32
  1039.                   chmod(save,HTS_ACCESS_FILE);      
  1040. #endif          
  1041.                 } else {
  1042.                   r.statuscode=STATUSCODE_INVALID;
  1043.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  1044.                   //printf("%s\n",save);
  1045.                 }
  1046.               }
  1047.               
  1048.             } else
  1049. #endif
  1050.             { // lire en mΘmoire
  1051.               
  1052.               if (pos<0) {
  1053.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  1054.                   r.statuscode=STATUSCODE_INVALID;
  1055.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  1056.                 } else {                 /* Read in memory from cache */
  1057.                   if (strnotempty(return_save) && fexist(return_save)) {
  1058.                     FILE* fp = fopen(fconv(catbuff, return_save), "rb");
  1059.                     if (fp != NULL) {
  1060.                       r.adr = (char*) malloct((size_t)r.size + 4);
  1061.                       if (r.adr != NULL) {
  1062.                         if (r.size > 0 && fread(r.adr, 1, (size_t)r.size, fp) != r.size) {
  1063.                           r.statuscode=STATUSCODE_INVALID;
  1064.                           strcpybuff(r.msg,"Read error in cache disk data");
  1065.                         }
  1066.                       } else {
  1067.                         r.statuscode=STATUSCODE_INVALID;
  1068.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  1069.                       }
  1070.                       fclose(fp);
  1071.                     }
  1072.                   } else {
  1073.                     r.statuscode=STATUSCODE_INVALID;
  1074.                     strcpybuff(r.msg,"Cache file not found on disk");
  1075.                   }
  1076.                 }
  1077.               } else {
  1078.                 // lire fichier (d'un coup)
  1079.                 r.adr=(char*) malloct((size_t)r.size+4);
  1080.                 if (r.adr!=NULL) {
  1081.                   if (fread(r.adr,1,(size_t)r.size,cache->olddat)!=r.size) {  // erreur
  1082.                     freet(r.adr);
  1083.                     r.adr=NULL;
  1084.                     r.statuscode=STATUSCODE_INVALID;
  1085.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  1086.                   } else
  1087.                     *(r.adr+r.size)='\0';
  1088.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  1089.                 } else {  // erreur
  1090.                   r.statuscode=STATUSCODE_INVALID;
  1091.                   strcpybuff(r.msg,"Cache Memory Error");
  1092.                 }
  1093.               }
  1094.             }
  1095.           }    // si save==null, ne rien charger (juste en tΩte)
  1096.         } else {
  1097. #if DEBUGCA
  1098.           printf("Cache Read Error : Bad Data");
  1099. #endif
  1100.           r.statuscode=STATUSCODE_INVALID;
  1101.           strcpybuff(r.msg,"Cache Read Error : Bad Data");
  1102.         }
  1103.       } else {  // erreur
  1104. #if DEBUGCA
  1105.         printf("Cache Read Error : Read Header");
  1106. #endif
  1107.         r.statuscode=STATUSCODE_INVALID;
  1108.         strcpybuff(r.msg,"Cache Read Error : Read Header");
  1109.       }
  1110.     } else {
  1111. #if DEBUGCA
  1112.       printf("Cache Read Error : Seek Failed");
  1113. #endif
  1114.       r.statuscode=STATUSCODE_INVALID;
  1115.       strcpybuff(r.msg,"Cache Read Error : Seek Failed");
  1116.     }
  1117.   } else {
  1118. #if DEBUGCA
  1119.     printf("File Cache Not Found");
  1120. #endif
  1121.     r.statuscode=STATUSCODE_INVALID;
  1122.     strcpybuff(r.msg,"File Cache Entry Not Found");
  1123.   }
  1124.   if (!location) {   /* don't export internal buffer */
  1125.     r.location = NULL;
  1126.   }
  1127.   return r;
  1128. }
  1129.  
  1130. /* write (string1-string2)-data in cache */
  1131. /* 0 if failed */
  1132. int cache_writedata(FILE* cache_ndx,FILE* cache_dat,const char* str1,const char* str2,char* outbuff,int len) {
  1133.   if (cache_dat) {
  1134.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1135.     char s[256];
  1136.     int pos;
  1137.     fflush(cache_dat); fflush(cache_ndx);
  1138.     pos=ftell(cache_dat);
  1139.     /* first write data */
  1140.     if (cache_wint(cache_dat,len)!=-1) {       // length
  1141.       if (fwrite(outbuff,1,len,cache_dat) == len) {   // data
  1142.         /* then write index */
  1143.         sprintf(s,"%d\n",pos);
  1144.         buff[0]='\0'; strcatbuff(buff,str1); strcatbuff(buff,"\n"); strcatbuff(buff,str2); strcatbuff(buff,"\n");
  1145.         cache_wstr(cache_ndx,buff);
  1146.         if (fwrite(s,1,strlen(s),cache_ndx) == strlen(s)) {
  1147.           fflush(cache_dat); fflush(cache_ndx);
  1148.           return 1;
  1149.         }
  1150.       }
  1151.     }
  1152.   }
  1153.   return 0;
  1154. }
  1155.  
  1156. /* read the data corresponding to (string1-string2) in cache */
  1157. /* 0 if failed */
  1158. int cache_readdata(cache_back* cache,const char* str1,const char* str2,char** inbuff,int* inlen) {
  1159. #if HTS_FAST_CACHE
  1160.   if (cache->hashtable) {
  1161.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1162.     intptr_t pos;
  1163.     strcpybuff(buff,str1); strcatbuff(buff,str2);
  1164.     if (inthash_read(cache->hashtable,buff,&pos)) {
  1165.       if (fseek(cache->olddat,(long)((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  1166.         INTsys len;
  1167.         cache_rint(cache->olddat,&len);
  1168.         if (len>0) {
  1169.           char* mem_buff=(char*)malloct(len+4);    /* Plus byte 0 */
  1170.           if (mem_buff) {
  1171.             if (fread(mem_buff,1,len,cache->olddat)==len) { // lire tout (y compris statuscode etc)*/
  1172.               *inbuff=mem_buff;
  1173.               *inlen=len;
  1174.               return 1;
  1175.             } else
  1176.               freet(mem_buff);
  1177.           }
  1178.         }
  1179.       }
  1180.     }
  1181.   }
  1182. #endif
  1183.   *inbuff=NULL;
  1184.   *inlen=0;
  1185.   return 0;
  1186. }
  1187.  
  1188. static int hts_rename(httrackp* opt, const char *a, const char *b) {
  1189.   if ((opt->debug>0) && (opt->log!=NULL)) {
  1190.     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: rename %s -> %s (%p %p)"LF, a, b, a, b);
  1191.   }
  1192.   return rename(a, b);
  1193. }
  1194.  
  1195. // renvoyer uniquement en tΩte, ou NULL si erreur
  1196. // return NULL upon error, and set -1 to r.statuscode
  1197. htsblk* cache_header(httrackp* opt,cache_back* cache,const char* adr,const char* fil,htsblk* r) {
  1198.   *r=cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  1199.   if (r->statuscode != -1)
  1200.     return r;
  1201.   else
  1202.     return NULL;
  1203. }
  1204.  
  1205.  
  1206. // Initialisation du cache: crΘer nouveau, renomer ancien, charger..
  1207. void cache_init(cache_back* cache,httrackp* opt) {
  1208.   // ---
  1209.   // utilisation du cache: renommer ancien Θventuel et charger index
  1210.   if ((opt->debug>0) && (opt->log!=NULL)) {
  1211.     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: enabled=%d, base=%s, ro=%d"LF, (int) opt->cache, fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/"), (int) cache->ro);
  1212.   }
  1213.   if (opt->cache) {
  1214. #if DEBUGCA
  1215.     printf("cache init: ");
  1216. #endif
  1217.     if (!cache->ro) {
  1218. #ifdef _WIN32
  1219.       mkdir(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache"));
  1220. #else
  1221.       mkdir(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache"),HTS_PROTECT_FOLDER);
  1222. #endif
  1223.       if ((fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1224.         /* Previous cache from the previous cache version */
  1225. #if 0
  1226.         /* No.. reuse with old httrack releases! */
  1227.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat")))
  1228.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"));
  1229.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx")))
  1230.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1231. #endif
  1232.         /* Previous cache version */
  1233.         if ((fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1234.           rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"));
  1235.           rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1236.         }
  1237.  
  1238.         /* Remove OLD cache */
  1239.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip"))) {
  1240.           if (remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip")) != 0) {
  1241.             int last_errno = errno;
  1242.             if (opt->log!=NULL) {
  1243.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: error while moving previous cache: %s"LF, strerror(last_errno));
  1244.             }
  1245.           }
  1246.         }
  1247.         
  1248.         /* Rename */
  1249.         if (hts_rename(opt, fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip"), fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip")) != 0) {
  1250.           int last_errno = errno;
  1251.           if (opt->log!=NULL) {
  1252.             HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: error while moving previous cache: %s"LF, strerror(last_errno));
  1253.           }
  1254.         } else {
  1255.           if ((opt->debug>0) && (opt->log!=NULL)) {
  1256.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: successfully renamed"LF);
  1257.           }
  1258.         }
  1259.       }
  1260.       else if ((fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1261. #if DEBUGCA
  1262.         printf("work with former cache\n");
  1263. #endif
  1264.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat")))
  1265.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"));
  1266.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx")))
  1267.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1268.         
  1269.         rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"));
  1270.         rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1271.       } else {  // un des deux (ou les deux) fichiers cache absents: effacer l'autre Θventuel
  1272. #if DEBUGCA
  1273.         printf("new cache\n");
  1274. #endif
  1275.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat")))
  1276.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"));
  1277.         if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx")))
  1278.           remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"));
  1279.       }
  1280.     } else {
  1281.       if ((opt->debug>0) && (opt->log!=NULL)) {
  1282.         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: no cache found"LF);
  1283.       }
  1284.     }
  1285.     if ((opt->debug>0) && (opt->log!=NULL)) {
  1286.       HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: size %d"LF, (int)fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip")));
  1287.     }
  1288.  
  1289.     // charger index cache prΘcΘdent
  1290.     if (
  1291.       (
  1292.       !cache->ro &&
  1293.       fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip")) > 0 
  1294.       )
  1295.       ||
  1296.       (
  1297.       cache->ro &&
  1298.       fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip")) > 0
  1299.       )
  1300.       ) 
  1301.     {
  1302.       if (!cache->ro) {
  1303.         cache->zipInput = unzOpen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip"));
  1304.       } else {
  1305.         cache->zipInput = unzOpen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip"));
  1306.       }
  1307.       
  1308.       // Corrupted ZIP file ? Try to repair!
  1309.       if (cache->zipInput == NULL && !cache->ro) {
  1310.         char* name;
  1311.         uLong repaired = 0;
  1312.         uLong repairedBytes = 0;
  1313.         if (!cache->ro) {
  1314.           name = fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.zip");
  1315.         } else {
  1316.           name = fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip");
  1317.         }
  1318.         if (opt->log) {
  1319.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: damaged cache, trying to repair"LF);
  1320.           fflush(opt->log);
  1321.         }
  1322.         if (unzRepair(name, 
  1323.           fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/repair.zip"),
  1324.           fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/repair.tmp"),
  1325.           &repaired, &repairedBytes
  1326.           ) == Z_OK) {
  1327.             unlink(name);
  1328.             rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/repair.zip"), name);
  1329.             cache->zipInput = unzOpen(name);
  1330.             if (opt->log) {
  1331.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: %d bytes successfully recovered in %d entries"LF, 
  1332.                 (int) repairedBytes, (int) repaired);
  1333.               fflush(opt->log);
  1334.             }
  1335.           } else {
  1336.             if (opt->log) {
  1337.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: could not repair the cache"LF);
  1338.               fflush(opt->log);
  1339.             }
  1340.           }
  1341.       }
  1342.       
  1343.       // Opened ?
  1344.       if (cache->zipInput!=NULL) {
  1345.         int zErr;
  1346.  
  1347.         /* Ready directory entries */
  1348.         if ( ( zErr = unzGoToFirstFile((unzFile) cache->zipInput) ) == Z_OK) {
  1349.           char comment[128];
  1350.           char BIGSTK filename[HTS_URLMAXSIZE * 4];
  1351.           int entries = 0;
  1352.           memset(comment, 0, sizeof(comment));       // for truncated reads
  1353.           do  {
  1354.             int readSizeHeader = 0;
  1355.             filename[0] = '\0';
  1356.             comment[0] = '\0';
  1357.             if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  1358.               if (
  1359.                 (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, comment, sizeof(comment) - 2)) > 0
  1360.                 &&
  1361.                 unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL, filename, sizeof(filename) - 2, NULL, 0, NULL, 0) == Z_OK
  1362.                 ) 
  1363.               {
  1364.                 long int pos = (long int) unzGetOffset((unzFile) cache->zipInput);
  1365.                 assertf(readSizeHeader < sizeof(comment));
  1366.                 comment[readSizeHeader] = '\0';
  1367.                 entries++;
  1368.                 if (pos > 0) {
  1369.                   int dataincache = 0;    // data in cache ?
  1370.                   char* filenameIndex = filename;
  1371.                   if (strfield(filenameIndex, "http://")) {
  1372.                     filenameIndex += 7;
  1373.                   }
  1374.                   if (comment[0] != '\0') {
  1375.                     int maxLine = 2;
  1376.                     char* a = comment;
  1377.                     while(*a && maxLine-- > 0) {      // parse only few first lines
  1378.                       char BIGSTK line[1024];
  1379.                       line[0] = '\0';
  1380.                       a+=binput(a, line, sizeof(line) - 2);
  1381.                       if (strfield(line, "X-In-Cache:")) {
  1382.                         if (strfield2(line, "X-In-Cache: 1")) {
  1383.                           dataincache = 1;
  1384.                         } else {
  1385.                           dataincache = 0;
  1386.                         }
  1387.                         break;
  1388.                       }
  1389.                     }
  1390.                   }
  1391.                   if (dataincache)
  1392.                     inthash_add(cache->hashtable, filenameIndex, pos);
  1393.                   else
  1394.                     inthash_add(cache->hashtable, filenameIndex, -pos);
  1395.                 } else {
  1396.                   if (opt->log!=NULL) {
  1397.                     HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Corrupted cache meta entry #%d"LF, (int)entries);
  1398.                   }
  1399.                 }
  1400.               } else {
  1401.                 if (opt->log!=NULL) {
  1402.                   HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1403.                 }
  1404.               }
  1405.               unzCloseCurrentFile((unzFile) cache->zipInput);
  1406.             } else {
  1407.               if (opt->log!=NULL) {
  1408.                 HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1409.               }
  1410.             }
  1411.           } while( unzGoToNextFile((unzFile) cache->zipInput) == Z_OK );
  1412.           if ((opt->debug>0) && (opt->log!=NULL)) {
  1413.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache index loaded: %d entries loaded"LF, (int)entries);
  1414.           }
  1415.           opt->is_update=1;        // signaler comme update
  1416.           
  1417.         } else {
  1418.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: error trying to read the cache: %s"LF, hts_get_zerror(zErr));
  1419.         }    
  1420.         
  1421.       } else {
  1422.         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: error trying to open the cache"LF);
  1423.       }
  1424.       
  1425.     } else if (
  1426.       (
  1427.       !cache->ro &&
  1428.       fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat")) >=0 && fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx")) >0
  1429.       )
  1430.       ||
  1431.       (
  1432.       cache->ro &&
  1433.       fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat")) >=0 && fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx")) > 0
  1434.       )
  1435.       ) {
  1436.       FILE* oldndx=NULL;
  1437. #if DEBUGCA
  1438.       printf("..load cache\n");
  1439. #endif
  1440.       if (!cache->ro) {
  1441.         cache->olddat=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"),"rb");        
  1442.         oldndx=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"),"rb");        
  1443.       } else {
  1444.         cache->olddat=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"),"rb");        
  1445.         oldndx=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"),"rb");        
  1446.       }
  1447.       // les deux doivent Ωtre ouvrables
  1448.       if ((cache->olddat==NULL) && (oldndx!=NULL)) {
  1449.         fclose(oldndx);
  1450.         oldndx=NULL;
  1451.       }
  1452.       if ((cache->olddat!=NULL) && (oldndx==NULL)) {
  1453.         fclose(cache->olddat);
  1454.         cache->olddat=NULL;
  1455.       }
  1456.       // lire index
  1457.       if (oldndx!=NULL) {
  1458.         int buffl;
  1459.         fclose(oldndx); oldndx=NULL;
  1460.         // lire ndx, et lastmodified
  1461.         if (!cache->ro) {
  1462.           buffl=fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1463.           cache->use=readfile(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"));
  1464.         } else {
  1465.           buffl=fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"));
  1466.           cache->use=readfile(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"));
  1467.         }
  1468.         if (cache->use!=NULL) {
  1469.           char firstline[256];
  1470.           char* a=cache->use;
  1471.           a+=cache_brstr(a,firstline);
  1472.           if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  1473.             if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  1474.               cache->version=(int)(firstline[8]-'0');           // cache 1.x
  1475.               if (cache->version <= 5) {
  1476.                 a+=cache_brstr(a,firstline);
  1477.                 strcpybuff(cache->lastmodified,firstline);
  1478.               } else {
  1479.                 if (opt->log) {
  1480.                   HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  1481.                   fflush(opt->log);
  1482.                 }
  1483.                 fclose(cache->olddat);
  1484.                 cache->olddat=NULL;
  1485.                 freet(cache->use);
  1486.                 cache->use=NULL;
  1487.               }
  1488.             } else {        // non supportΘ
  1489.               if (opt->log) {
  1490.                 HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Cache: %s not supported, ignoring current cache"LF,firstline);
  1491.                 fflush(opt->log);
  1492.               }
  1493.               fclose(cache->olddat);
  1494.               cache->olddat=NULL;
  1495.               freet(cache->use);
  1496.               cache->use=NULL;
  1497.             }
  1498.             /* */
  1499.           } else {              // Vieille version du cache
  1500.             /* */
  1501.             if (opt->log) {
  1502.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Cache: importing old cache format"LF);
  1503.               fflush(opt->log);
  1504.             }
  1505.             cache->version=0;        // cache 1.0
  1506.             strcpybuff(cache->lastmodified,firstline); 
  1507.           }
  1508.           opt->is_update=1;        // signaler comme update
  1509.           
  1510.           /* Create hash table for the cache (MUCH FASTER!) */
  1511. #if HTS_FAST_CACHE
  1512.           if (cache->use) {
  1513.             char BIGSTK line[HTS_URLMAXSIZE*2];
  1514.             char linepos[256];
  1515.             int  pos;
  1516.             while ( (a!=NULL) && (a < (cache->use+buffl) ) ) {
  1517.               a=strchr(a+1,'\n');     /* start of line */
  1518.               if (a) {
  1519.                 a++;
  1520.                 /* read "host/file" */
  1521.                 a+=binput(a,line,HTS_URLMAXSIZE);
  1522.                 a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  1523.                 /* read position */
  1524.                 a+=binput(a,linepos,200);
  1525.                 sscanf(linepos,"%d",&pos);
  1526.                 inthash_add(cache->hashtable,line,pos);
  1527.               }
  1528.             }
  1529.             /* Not needed anymore! */
  1530.             freet(cache->use);
  1531.             cache->use=NULL;
  1532.           }
  1533. #endif
  1534.         }
  1535.       }
  1536.       } else {
  1537.         if ((opt->debug>0) && (opt->log!=NULL)) {
  1538.           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: no cache found in %s"LF, fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/"));
  1539.         }
  1540.       }
  1541.  
  1542. #if DEBUGCA
  1543.       printf("..create cache\n");
  1544. #endif
  1545.       if (!cache->ro) {
  1546.         // ouvrir caches actuels
  1547.         structcheck(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log), "hts-cache/"));
  1548.  
  1549.         if (1) {
  1550.           /* Create ZIP file cache */
  1551.           cache->zipOutput = (void*) zipOpen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.zip"), 0);
  1552.  
  1553.           if (cache->zipOutput != NULL) {
  1554.             // supprimer old.lst
  1555.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst")))
  1556.               remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"));
  1557.             // renommer
  1558.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst")))
  1559.               rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"));
  1560.             // ouvrir
  1561.             cache->lst=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"),"wb");
  1562.             strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
  1563.             opt->state.strc.lst = cache->lst;
  1564.             //{
  1565.             //filecreate_params tmp;
  1566.             //strcpybuff(tmp.path,StringBuff(opt->path_html));    // chemin
  1567.             //tmp.lst=cache->lst;                 // fichier lst
  1568.             //filenote("",&tmp);        // initialiser filecreate
  1569.             //}
  1570.  
  1571.             // supprimer old.txt
  1572.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt")))
  1573.               remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt"));
  1574.             // renommer
  1575.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt")))
  1576.               rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt"));
  1577.             // ouvrir
  1578.             cache->txt=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"),"wb");
  1579.             if (cache->txt) {
  1580.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1581.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1582.             }
  1583.           }
  1584.         } else {
  1585.           cache->dat=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"),"wb");        
  1586.           cache->ndx=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"),"wb");        
  1587.           // les deux doivent Ωtre ouvrables
  1588.           if ((cache->dat==NULL) && (cache->ndx!=NULL)) {
  1589.             fclose(cache->ndx);
  1590.             cache->ndx=NULL;
  1591.           }
  1592.           if ((cache->dat!=NULL) && (cache->ndx==NULL)) {
  1593.             fclose(cache->dat);
  1594.             cache->dat=NULL;
  1595.           }
  1596.  
  1597.           if (cache->ndx!=NULL) {
  1598.             char s[256];
  1599.  
  1600.             cache_wstr(cache->dat,"CACHE-1.5");
  1601.             fflush(cache->dat);
  1602.             cache_wstr(cache->ndx,"CACHE-1.5");
  1603.             fflush(cache->ndx);
  1604.             //
  1605.             time_gmt_rfc822(s);   // date et heure actuelle GMT pour If-Modified-Since..
  1606.             cache_wstr(cache->ndx,s);        
  1607.             fflush(cache->ndx);    // un petit fflush au cas o∙
  1608.  
  1609.             // supprimer old.lst
  1610.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst")))
  1611.               remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"));
  1612.             // renommer
  1613.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst")))
  1614.               rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"));
  1615.             // ouvrir
  1616.             cache->lst=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"),"wb");
  1617.             strcpybuff(opt->state.strc.path, StringBuff(opt->path_html));
  1618.             opt->state.strc.lst = cache->lst;
  1619.             //{
  1620.             //  filecreate_params tmp;
  1621.             //  strcpybuff(tmp.path,StringBuff(opt->path_html));    // chemin
  1622.             //  tmp.lst=cache->lst;                 // fichier lst
  1623.             //  filenote("",&tmp);        // initialiser filecreate
  1624.             //}
  1625.  
  1626.             // supprimer old.txt
  1627.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt")))
  1628.               remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt"));
  1629.             // renommer
  1630.             if (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt")))
  1631.               rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"),fconcat(OPT_GET_BUFF(opt),StringBuff(opt->path_log),"hts-cache/old.txt"));
  1632.             // ouvrir
  1633.             cache->txt=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"),"wb");
  1634.             if (cache->txt) {
  1635.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1636.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1637.             }
  1638.  
  1639.             // test
  1640.             // cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
  1641.           } // cache->ndx!=NULL
  1642.         } //cache->zipOutput != NULL
  1643.  
  1644.       } else {
  1645.         cache->lst = cache->dat = cache->ndx = NULL;
  1646.       }
  1647.       
  1648.   } else {
  1649.     if ((opt->debug>0) && (opt->log!=NULL)) {
  1650.       HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Cache: no cache enabled"LF);
  1651.     }
  1652.   }
  1653.   
  1654. }
  1655.  
  1656.  
  1657.  
  1658.  
  1659. // lire un fichier.. (compatible \0)
  1660. char* readfile(char* fil) {
  1661.   return readfile2(fil, NULL);
  1662. }
  1663.  
  1664. char* readfile2(char* fil, LLint* size) {
  1665.   char* adr=NULL;
  1666.     char catbuff[CATBUFF_SIZE];
  1667.   INTsys len=0;
  1668.   len=fsize(fil);
  1669.   if (len >= 0) {  // exists
  1670.     FILE* fp;
  1671.     fp=fopen(fconv(catbuff, fil),"rb");
  1672.     if (fp!=NULL) {  // n'existe pas (!)
  1673.       adr=(char*) malloct(len+1);
  1674.       if (size != NULL)
  1675.         *size = len;
  1676.       if (adr!=NULL) {
  1677.         if (len > 0 && fread(adr,1,len,fp) != len) {    // fichier endommagΘ ?
  1678.           freet(adr);
  1679.           adr=NULL;
  1680.         } else
  1681.           *(adr+len)='\0';
  1682.       }
  1683.       fclose(fp);
  1684.     }
  1685.   }
  1686.   return adr;
  1687. }
  1688.  
  1689. char* readfile_or(char* fil,char* defaultdata) {
  1690.   char* realfile=fil;
  1691.   char* ret;
  1692.     char catbuff[CATBUFF_SIZE];
  1693.   if (!fexist(fil))
  1694.     realfile=fconcat(catbuff,hts_rootdir(NULL),fil);
  1695.   ret=readfile(realfile);
  1696.   if (ret)
  1697.     return ret;
  1698.   else {
  1699.     char *adr=malloct(strlen(defaultdata)+2);
  1700.     if (adr) {
  1701.       strcpybuff(adr,defaultdata);
  1702.       return adr;
  1703.     }
  1704.   }
  1705.   return NULL;
  1706. }
  1707.  
  1708. // Θcriture/lecture d'une chaεne sur un fichier
  1709. // -1 : erreur, sinon 0
  1710. int cache_wstr(FILE* fp,const char* s) {
  1711.   INTsys i;
  1712.   char buff[256+4];
  1713.   i = (s != NULL) ? ((INTsys)strlen(s)) : 0;
  1714.   sprintf(buff,INTsysP "\n",i);
  1715.   if (fwrite(buff,1,strlen(buff),fp) != strlen(buff))
  1716.     return -1;
  1717.   if (i > 0 && fwrite(s,1,i,fp) != i)
  1718.     return -1;
  1719.   return 0;
  1720. }
  1721. void cache_rstr(FILE* fp,char* s) {
  1722.   INTsys i;
  1723.   char buff[256+4];
  1724.   linput(fp,buff,256);
  1725.   sscanf(buff,INTsysP,&i);
  1726.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1727.     i=0;
  1728.   if (i>0) {
  1729.     if ((int) fread(s,1,i,fp) != i) {
  1730.       int fread_cache_failed = 0;
  1731.       assertf(fread_cache_failed);
  1732.     }
  1733.   }
  1734.   *(s+i)='\0';
  1735. }
  1736. char* cache_rstr_addr(FILE* fp) {
  1737.   INTsys i;
  1738.   char* addr = NULL;
  1739.   char buff[256+4];
  1740.   linput(fp,buff,256);
  1741.   sscanf(buff,INTsysP,&i);
  1742.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1743.     i=0;
  1744.   if (i > 0) {
  1745.     addr = malloct(i + 1);
  1746.     if (addr != NULL) {
  1747.       if ((int) fread(addr,1,i,fp) != i) {
  1748.         int fread_cache_failed = 0;
  1749.         assertf(fread_cache_failed);
  1750.       }
  1751.       *(addr+i)='\0';
  1752.     }
  1753.   }
  1754.   return addr;
  1755. }
  1756. int cache_brstr(char* adr,char* s) {
  1757.   int i;
  1758.   int off;
  1759.   char buff[256+4];
  1760.   off=binput(adr,buff,256);
  1761.   adr+=off;
  1762.   sscanf(buff,"%d",&i);
  1763.   if (i>0)
  1764.     strncpy(s,adr,i);
  1765.   *(s+i)='\0';
  1766.   off+=i;
  1767.   return off;
  1768. }
  1769. int cache_quickbrstr(char* adr,char* s) {
  1770.   int i;
  1771.   int off;
  1772.   char buff[256+4];
  1773.   off=binput(adr,buff,256);
  1774.   adr+=off;
  1775.   sscanf(buff,"%d",&i);
  1776.   if (i>0)
  1777.     strncpy(s,adr,i);
  1778.   *(s+i)='\0';
  1779.   off+=i;
  1780.   return off;
  1781. }
  1782. /* idem, mais en int */
  1783. int cache_brint(char* adr,int* i) {
  1784.   char s[256];
  1785.   int r=cache_brstr(adr,s);
  1786.   if (r!=-1)
  1787.     sscanf(s,"%d",i);
  1788.   return r;
  1789. }
  1790. void cache_rint(FILE* fp,int* i) {
  1791.   char s[256];
  1792.   cache_rstr(fp,s);
  1793.   sscanf(s,"%d",i);
  1794. }
  1795. int cache_wint(FILE* fp,int i) {
  1796.   char s[256];
  1797.   sprintf(s,"%d",(int) i);
  1798.   return cache_wstr(fp,s);
  1799. }
  1800. void cache_rLLint(FILE* fp,LLint* i) {
  1801.   char s[256];
  1802.   cache_rstr(fp,s);
  1803.   sscanf(s,LLintP,i);
  1804. }
  1805. int cache_wLLint(FILE* fp,LLint i) {
  1806.   char s[256];
  1807.   sprintf(s,LLintP,(LLint) i);
  1808.   return cache_wstr(fp,s);
  1809. }
  1810. // -- cache --
  1811.